import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.ExportException;

import javax.swing.table.DefaultTableModel;

import FlexTrade.AuctionPrimitiveData;
import FlexTrade.AuctionStates;
import FlexTrade.BidPriceData;
import FlexTrade.FlexTradeUtils;
import FlexTrade.IAuction;
import FlexTrade.IMarketService;
import net.jini.core.discovery.LookupLocator;
import net.jini.core.entry.Entry;
import net.jini.core.event.RemoteEvent;
import net.jini.core.event.RemoteEventListener;
import net.jini.core.event.UnknownEventException;
import net.jini.core.lookup.ServiceItem;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.lookup.ServiceTemplate;
import net.jini.discovery.LookupDiscovery;
import net.jini.discovery.LookupDiscoveryManager;
import net.jini.export.Exporter;
import net.jini.jeri.BasicILFactory;
import net.jini.jeri.BasicJeriExporter;
import net.jini.jeri.tcp.TcpServerEndpoint;
import net.jini.lease.LeaseRenewalManager;
import net.jini.lookup.ServiceDiscoveryManager;
import net.jini.lookup.entry.Name;

public class Provider extends Thread implements Remote, RemoteEventListener {
	  //name of market service	
	  private static String FLEXTRADE_SERVICE_NAME = "FlexTradeService";
	  private static final long WAITFOR = 100000L;
	  
	  //market service
	  public IMarketService market_service = null;
	  //current active auction in this provider object
	  public IAuction activeAuction;
	  //Provider information

	  private RemoteEventListener proxy = null;
	  //reference to the text field in main frame UI
	  public javax.swing.JTextArea txtText = null;
	  //detail information of this auction.
	  public AuctionPrimitiveData auctionPrimitiveData;
	  //table model
	  public DefaultTableModel model;
	
	/**
	 * @param args
	 */

	public Provider() {
		lookUpMarketService();
	}

	//Setup LookupDiscoveryManager (LUS) and look for IMarketService object
	private void lookUpMarketService() {
		LookupLocator lookup = null;
		ServiceRegistrar registrar = null;
		try {
			lookup = new LookupLocator("jini://localhost");
		} catch(java.net.MalformedURLException e) {
			System.err.println("Lookup failed: " + e.toString());
		}
		try {
			registrar = lookup.getRegistrar();
		} catch (java.io.IOException e) {
			System.err.println("Registrar search failed: " + e.toString());
		} catch (java.lang.ClassNotFoundException e) {
			System.err.println("Registrar search failed: " + e.toString());
		}
		
		try	{
			Entry[] serverAttributes = new Entry[1];
			//Create template to find FlexTrade service by name
		    serverAttributes[0] = new Name (Provider.FLEXTRADE_SERVICE_NAME);
		    ServiceTemplate template = 
		    		  new ServiceTemplate (null, null, serverAttributes);
			this.market_service = (IMarketService) registrar.lookup (template);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}
	
	//Place a new auction into LUS with data in _auctionPrimitiveData
	//_auctionPrimitiveData is collected from NewAuctionDlg form
	public void requestNewAuction(AuctionPrimitiveData _auctionPrimitiveData) {
		try{
			Exporter exporter = new BasicJeriExporter(
					TcpServerEndpoint.getInstance(0),
					new BasicILFactory());
					// export an object of this class and get proxy
			try {
				//proxy will be registered as event listener of auction object.
				proxy = (RemoteEventListener) exporter.export(this);
			} catch (ExportException e) {
				e.printStackTrace();
			}
			//proxy is added as RemoteEventListener to IAuction object in space
			market_service.receiveNewAuctionRequestFromProvider(_auctionPrimitiveData, proxy);
			this.auctionPrimitiveData = _auctionPrimitiveData;
			//display notification of auction request
			String messageLog = FlexTradeUtils.currentTime() + ": New auction with ID ";
			messageLog = messageLog + auctionPrimitiveData.uniqueAuctionID + " has been created.";
			this.setText(messageLog);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void notify(RemoteEvent arg0) throws UnknownEventException, RemoteException {
		// TODO Auto-generated method stub
		String messageLog = "";
		int eventID = (int) arg0.getID();
		IAuction sourceAuction = (IAuction) arg0.getSource();
		BidPriceData bidPriceData;
		//get the current status of this auction
		AuctionStates auctionStates = sourceAuction.getCurrentAuctionStates();
		switch(eventID){
		
		case IAuction.E_AUCTION_FINISH:
			messageLog = (FlexTradeUtils.currentTime() + ": Auction " +  sourceAuction.getUniqueAuctionID() + " is finished");
			break;
		
		case IAuction.E_BID_PRICE_RECEIVED:
			bidPriceData = sourceAuction.getLastBidPriceData();
			messageLog = FlexTradeUtils.currentTime() + ": Received bid price of " + bidPriceData.getBidPrice() + " from customer ";
			messageLog = messageLog + bidPriceData.customer.getUniqueCustomerID() + " for auction";
			messageLog = messageLog + sourceAuction.getUniqueAuctionID();
			break;
		
		case IAuction.E_CUSTOMER_JOIN:
			messageLog = FlexTradeUtils.currentTime() + ": New customer has just joined the auction " + sourceAuction.getUniqueAuctionID();
			break;
		
		case IAuction.V_AUCTION_FINISH:
			messageLog = (FlexTradeUtils.currentTime() + ": Auction " +  sourceAuction.getUniqueAuctionID() + " is finished");
			break;
		
		case IAuction.V_BID_PRICE_RECEIVED:
			bidPriceData = sourceAuction.getLastBidPriceData();
			messageLog = FlexTradeUtils.currentTime() + ": Received bid price of " + bidPriceData.getBidPrice() + " from customer  ";
			messageLog = messageLog + bidPriceData.customer.getUniqueCustomerID() + " for auction ";
			messageLog = messageLog + sourceAuction.getUniqueAuctionID();
			break;
		
		case IAuction.V_CUSTOMER_JOIN:
			messageLog = FlexTradeUtils.currentTime() + ": New customer has just joined the auction " + sourceAuction.getUniqueAuctionID();
			break;
		
		case IAuction.D_ACCEPTABLE_PRICE_RECEIVED:
			messageLog = FlexTradeUtils.currentTime() + ": Received new offer of ";
			messageLog = messageLog + Float.toString(auctionStates.acceptableBidPrice) + " for auction ID "; 
			messageLog = messageLog + sourceAuction.getUniqueAuctionID();
			break;
	
		case IAuction.D_CUSTOMER_JOIN:
			messageLog = FlexTradeUtils.currentTime() + ": New customer has just joined the auction " + sourceAuction.getUniqueAuctionID();
			break;

		case IAuction.D_CUSTOMER_ACCEPT:
			bidPriceData = sourceAuction.getLastBidPriceData();
			messageLog = FlexTradeUtils.currentTime() + ": Customer " + bidPriceData.customer.getUniqueCustomerID();
			messageLog = messageLog + " accepted price of " + bidPriceData.getBidPrice() + " for auction ID ";
			messageLog = messageLog + sourceAuction.getUniqueAuctionID();
			break;
		
		case IAuction.D_AUCTION_TIMEOUT:
			messageLog = FlexTradeUtils.currentTime() + " Auction ID " + sourceAuction.getUniqueAuctionID();
			messageLog = messageLog + " is time out. No customer accepts your offer.";
			break;
			
		case IAuction.CANNOT_TRANSFER_PAYMENT:
			messageLog = FlexTradeUtils.currentTime() + ": Error. Payment transaction for auction  " + sourceAuction.getUniqueAuctionID();
			messageLog = messageLog + " is not successful. This auction is aborted.";
			break;
			
		case IAuction.PAYMENT_TRANSFERED_SUCCESSFULLY:
			messageLog = FlexTradeUtils.currentTime() + ": Payment transaction for auction  " + sourceAuction.getUniqueAuctionID();
			messageLog = messageLog + " is successful. Prepare to ship goods to customer";
			break;
		
		default:
			System.out.println(FlexTradeUtils.currentTime() + ": Invalid event ID occurs");	
		}
		//diplay logging message to main frame UI
		this.setText(messageLog);
	}
	
	public void setTableModel(DefaultTableModel _model) {
		this.model = _model;
	}
	
	public DefaultTableModel getTableModel(){
		return this.model;
	}
	
	//Get reference to text area in main form
	public void setTextField(javax.swing.JTextArea txt){
		this.txtText = txt;
	}
	
	//Print message to textfield in main form
	public void setText(String message){
		txtText.append("\n" + message);
	}
	
	public static IAuction lookUpCurrentAuction(String _uniqueAuctionID) {
		ServiceDiscoveryManager clientMgr = null;
		try {
			LookupDiscoveryManager mgr = new LookupDiscoveryManager(LookupDiscovery.ALL_GROUPS,
																	null, // unicast locators
																	null); // DiscoveryListener
			clientMgr = new ServiceDiscoveryManager(mgr, new LeaseRenewalManager());
		} catch(Exception e) {
			e.printStackTrace();
			return null;
		}
		//Create template to find FlexTrade service by name
		Entry[] serverAttributes = new Entry[1];
	    serverAttributes[0] = new Name (_uniqueAuctionID);
	    ServiceTemplate template = 
	    		  new ServiceTemplate (null, null, serverAttributes);
		
	    ServiceItem item = null;
		// Try to find the service, blocking until timeout if necessary
		try {
			item = clientMgr.lookup(template,
										null, // no filter
										Provider.WAITFOR); // timeout
		} catch(Exception e) {
			e.printStackTrace();
			return null;
		}
		if (item == null) {
			// couldn't find a service in time
			System.out.println("No auction service.");
			return null;
		}
		// Get the service
		IAuction returnAuction = (IAuction) item.service;
		if (returnAuction == null) {
			System.out.println("IAuction object is null.");
			return null;
		}
		return returnAuction;
	}
}